package com.focus.pay.core.handler;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.focus.pay.core.annation.PayOrderHandler;
import com.focus.pay.core.action.PayOrderAction;
import com.focus.pay.core.exception.ExceptionEnum;
import com.focus.pay.core.exception.PayException;
import com.focus.pay.core.utils.AssertUtils;
import com.focus.pay.core.utils.StringUtils;
import org.reflections.Reflections;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class PayOrderHandlerDistribute {

    private static final Log log = LogFactory.get();

    private static String scanPackage = "com.focus.pay";
    private static String format = "%s#%s#%s#%s";

    public static Map<String, Class> map;

    /**
     * 扫描注解,加载到容器
     */
    static {
        map = new Reflections(scanPackage).getTypesAnnotatedWith(PayOrderHandler.class).stream()
                .collect(Collectors.toMap(
                        item -> {
                            PayOrderHandler orderHandler = item.getAnnotation(PayOrderHandler.class);
                            String channel = orderHandler.channel().toString();
                            String channelType = orderHandler.channelType();
                            String version = orderHandler.version();
                            String extension = orderHandler.extension();
                            return String.format(format, channel,channelType, version, extension);
                        },
                        item -> item
                ));
        log.info("加载支付处理类：{}",map);
    }

    private PayOrderHandlerDistribute() {}


    /**
     * 执行方法
     *
     * @param payAction 执行内容
     * @param <T>       返回类型
     * @return 返回参数
     */
    public static <T> T action(PayOrderAction payAction) {
        String channel = payAction.getChannel().toString();
        String channelType = payAction.getChannelType();
        String payVersion = Objects.isNull(payAction.getVersion()) ? StringUtils.EMPTY : payAction.getVersion();
        String extension = Objects.isNull(payAction.getExtension()) ? StringUtils.EMPTY : payAction.getExtension();
        String handlerKey = String.format(format, channel, channelType, payVersion, extension);

        try {
            //判断容器是否包含执行类
            AssertUtils.notNull(map.get(handlerKey), () -> new PayException(ExceptionEnum.HANDLE_ERROR));
            //获取执行类
            Class clz = map.get(handlerKey);
            //获取执行方法
            Method method = clz.getMethod(payAction.getMethod(), payAction.getModel().getClass(), payAction.getConfig().getClass());
            //反射调用
            return (T) method.invoke(clz.newInstance(), payAction.getModel(), payAction.getConfig());

        } catch (PayException payException) {
            log.error(payException.getExceptionMsg() + "PayHandler:[" + handlerKey + "]", payException);
            return null;
        } catch (NoSuchMethodException exception) {
            log.error("未找到执行方法", exception);
            return null;
        } catch (Exception e) {
            log.error("未知异常", e);
            return null;
        }
    }
}
